﻿using FrameServer.Handler;
using Google.Protobuf;
using System;
using System.Globalization;
using System.Net;
using System.Net.Sockets;

namespace FrameServer.Net
{
    class TCPClientPeer
    {
        //数据接收缓冲
        private NetPacket message;

        //客户端tcp套接字
        private Socket tcpSocket;
        //客户端tcp IPEndPoint
        public IPEndPoint tcpIPEndPoint;

        //该玩家的一些属性
        public string token = "";



        //心跳包相关
        //客户端每隔一定时间发送心跳包，服务器接受的时候将此变量置为true。
        public bool heartBeatFlag = true;
        public int lackNum = 0;
        public TCPClientPeer(Socket clientSocket)
        {
            try
            {
                tcpSocket = clientSocket;
                tcpIPEndPoint = tcpSocket.RemoteEndPoint as IPEndPoint;
                message = new NetPacket();
                clientSocket.BeginReceive(message.buffer, message.Start, message.Remain, SocketFlags.None, ReceiveCallBack, null);
            }
            catch (Exception e)
            {
                LogUtil.Log(e, LogLevel.EROR);
            }
        }

        private void ReceiveCallBack(IAsyncResult asyncResult)
        {
            try
            {
                int count = tcpSocket.EndReceive(asyncResult);
                if (count <= 0)
                {
                    LogUtil.Log($"TCP连接释放，客户端主动断开连接", LogLevel.WARN);
                    TCPServer.Instance.RemoveTCPClientPeer(this);
                    return;
                }
                message.UnpackMessage(count, HandleRequest);

                tcpSocket.BeginReceive(message.buffer, message.Start, message.Remain, SocketFlags.None, ReceiveCallBack, null);
            }
            catch (Exception e)
            {
                LogUtil.Log($"TCP连接释放，客户端强制断开连接。"+e, LogLevel.WARN);
                TCPServer.Instance.RemoveTCPClientPeer(this);
            }
        }

        private void HandleRequest(byte byteMsgId, byte[] parameters)
        {
            NetMsgID msgId = (NetMsgID)byteMsgId;
            NetMsgHandler.Instance.HandleReq(msgId, parameters, this);
            LogRcv(msgId, parameters);
        }


        //客户端已断开连接，释放所有相关资源
        public void CloseTcpClient()
        {
            message = null;
            if (tcpSocket != null)
            {
                try
                {
                    TCPServer.Instance.tcpClients.Remove(this);
                    TCPServer.Instance.clientPeerMap.Remove(this.token);
                    LogUtil.Log($"{this.tcpIPEndPoint}被从tcpClients列表移除，剩余长度: {TCPServer.Instance.tcpClients.Count}");

                    if (tcpSocket.Connected)
                    {
                        tcpSocket.Shutdown(SocketShutdown.Both);
                        tcpSocket.Close();
                    }
                    tcpSocket = null;
                }
                catch (Exception e)
                {
                    LogUtil.Log("关闭连接时出现错误" + e, LogLevel.WARN);
                }
            }
        }

        public void SendTcpMsg(NetMsgID msgId, IMessage parameter) {
            try
            {
                byte[] data = NetPacket.PackMessage(msgId, parameter);
                tcpSocket.Send(data);
                LogSend(msgId, parameter);
            }
            catch (Exception e)
            {
                LogUtil.Log($"发送TCP消息失败，连接将会被释放。" + e, LogLevel.WARN);
                TCPServer.Instance.RemoveTCPClientPeer(this);
            }
        }

        /// <summary>判断当前Peer是否断开连接</summary>
        public bool IsConnected() {
            return !tcpSocket.Poll(1000, SelectMode.SelectRead);
        }

        private void LogSend(NetMsgID msgId, IMessage data) {
            switch (msgId) {
                case NetMsgID.ScSyncState:
                    break;
                case NetMsgID.ScNtfStates:
                    break;
                default:
                    LogUtil.Log($"-->tcp:{tcpIPEndPoint}:{msgId}:{data}");
                    break;
            }
        }
        private void LogRcv(NetMsgID msgId, byte[] data) {
            switch (msgId)
            {
                case NetMsgID.CsHeartBeat:
                    break;
                case NetMsgID.CsSyncState:
                    break;
                default:
                    LogUtil.Log($"<--tcp:{tcpIPEndPoint}:{msgId}:[...{data.Length}]");
                    break;
            }
        }
    }
}
